﻿#include "stdafx.h"
#ifdef LK_RANDOM_
namespace LK
{

	Random::Random() :arr(new LK::Collection::DefaultArray<u64>(5))
	{
		u64 *p = GetArray();
		u8* pm = (u8*)(p + 3);
		pm[0] = ((u64)PTime::GetLocal()) % 62 + 1;
		for (size_t i = 1; i < 3; ++i)
		{
			p[i + 1] = (p[i] << 1) | ((s64)p[i] < 0);
			pm[i] = (Rand() % 62) + 1;
			if (pm[i] == pm[i - 1])if (++pm[i] > 63)pm[i] = 1;
		}
		p[4] = 0;
	}
	Random& Random::operator= (const Random& v)
	{
		if (v.arr.IsNull())return*this;
		if (v.GetArray().GetLength() > GetArray().GetLength())GetArray().Resize(v.GetArray().GetLength());
		u64*p1 = GetArray();
		const u64*p2 = v.GetArray();
		for (index_t i = 0; i < v.GetArray().GetLength(); ++i)*p1++ = *p2++;
		return *this;
	}
	Random::Random(Random const &vr) :arr(vr.arr.CastTo<PCloneables>().Clone()) {}
	void Random::SwapWith(Random& x)
	{
		if (arr.IsNull()) { x.GetArray().ResetTo(0); return; }
		PObject::SwapReference(arr, x.arr);
		if (arr.IsNull())arr = x.arr.CastTo<PCloneables>().Clone();
		else if (GetArray().GetLength() < x.GetArray().GetLength())GetArray().Resize(x.GetArray().GetLength());
	}
	Random::Random(unsigned long long seed, size_t len) :arr(new LK::Collection::DefaultArray<u64>(len + 2 + (len + 17) / 8))
	{
		SetNextRand(seed);
	}
	Random::Random(const Collection::PArray<u64> a) : arr(a) {}
	void Random::SetNextRand(unsigned long long next)
	{
		u64* p = GetArray();
		index_t idx = GetArray().GetLength() - 1;
		index_t len = idx * 8 / 9;
		u8* pm = (u8*)(p + len);
		p[0] = 0x5c8173df2b96e40a;//这个数字是随意设置的
		pm[0] = next % 62 + 1;
		for (index_t i = 1; i < len; ++i)
		{
			p[i + 1] = (p[i] << 1) | ((s64)p[i] < 0);
			pm[i] = (PRandom::GetDefaultRef().Rand() % 62) + 1;
			if (pm[i] == pm[i - 1])if (++pm[i] > 63)pm[i] = 1;
		}
		p[idx] = 0;
		p[(idx * 8 / 9) / 2] = next^p[0];
	}
	void Random::SetNextRandStatic(unsigned long long next)
	{
		u64* p = GetArray();
		index_t idx = GetArray().GetLength() - 1;
		index_t len = idx * 8 / 9;
		u8* pm = (u8*)(p + len);
		p[0] = 0x5c8173df2b96e40a;//这个数字是随意设置的
		pm[0] = next % 62 + 1;
		for (index_t i = 1; i < len; ++i)
		{
			p[i + 1] = (p[i] << 1) | ((s64)p[i] < 0);
			pm[i] = (p[i - 1] % 62) + 1;
			if (pm[i] == pm[i - 1])if (++pm[i] > 63)pm[i] = 1;
		}
		p[idx] = 0;
		p[(idx * 8 / 9) / 2] = next^p[0];
	}
	unsigned long long Random::Rand()
	{
		index_t idx = GetArray().GetLength() - 1;
		index_t len = idx * 8 / 9;
		u64*p = GetArray();
		if ((index_t)++(p[idx]) >= len / 2)
		{
			p[idx] = 0;
			u8* pm = (u8*)(p + len);
			p[0] = ((p[0] << pm[0]) | (p[0] >> (64 - pm[0]))) + p[len - 1] + 1;
			for (index_t i = 1; i < len; ++i)p[i] = ((p[i] << pm[i]) | (p[i] >> (64 - pm[i]))) + p[i - 1] + 1;
		}
		return p[p[idx]] ^ p[p[idx] + len / 2];
	}
	unsigned long long Random::SecretRand()
	{
		GetArray()[0] ^= Time::GetLocalTick(); return Rand();
	}
	Random::operator unsigned long long()const
	{
		return const_cast<Random*>(this)->Rand();
	}

	double Random::NextDouble()
	{
		return (Rand() >> 11) * (1.0 / 9007199254740992.0);
	}
	signed int Random::NextInt()
	{
		return 0x7fffffff & Rand();
	}
	signed short Random::NextShort()
	{
		return 0x7fff & Rand();
	}
	signed char Random::NextChar()
	{
		return 0x7f & Rand();
	}
	unsigned int Random::NextUInt()
	{
		return (unsigned int)Rand();
	}
	unsigned short Random::NextUShort()
	{
		return (unsigned short)Rand();
	}
	unsigned char Random::NextUChar()
	{
		return (unsigned char)Rand();
	}
#ifdef _CLR //托管支持
	Random& Random::operator=(System::Random^r)
	{
		SetNextRand((unsigned long long)r->NextDouble()*MaxValues::UnsignedLongLong);
		return *this;
	}
#endif
	Mt64Random::Mt64Random() :Random(new LK::Collection::DefaultArray<u64>(313)) { SetNextRandStatic(Time::GetLocalTick()); }
	Mt64Random::Mt64Random(u64 seed) { SetNextRandStatic(seed); }
	void Mt64Random::SetNextRand(u64 seed)
	{
		SetNextRandStatic(seed);
	}
	void Mt64Random::SetNextRandStatic(u64 seed)
	{
		u64* p = GetArray();
		p[312] = 0;
		p[0] = seed;
		for (int i = 1; i < 312; i++)
			p[i] = (6364136223846793005ull * (p[i - 1] ^ (p[i - 1] >> 62)) + i);
	}
	u64 Mt64Random::Rand()
	{
		u64* p = GetArray();
		if (p[312] >= 312) { p[312] = 0; Generate(); }
		u64 x = p[p[312]++];
		x ^= (x >> 29) & 0x5555555555555555ull;
		x ^= (x << 17) & 0x71D67FFFEDA60000ull;
		x ^= (x << 37) & 0xFFF7EEE000000000ull;
		return x ^ (x >> 43);
	}
	void Mt64Random::Generate()
	{
		u64* p = GetArray();
		index_t i;
		u64 x;
		for (i = 0; i < 156; i++) {
			x = (p[i] & 0xFFFFFFFF80000000ull) | (p[i + 1] & 0x7FFFFFFFull);
			if (x & 1)p[i] = p[i + 156] ^ (x >> 1) ^ 0xB5026F5AA96619E9ull;
			else p[i] = p[i + 156] ^ (x >> 1);
		}
		for (; i < 311; i++) {
			x = (p[i] & 0xFFFFFFFF80000000ull) | (p[i + 1] & 0x7FFFFFFFull);
			if (x & 1)p[i] = p[i - 156] ^ (x >> 1) ^ 0xB5026F5AA96619E9ull;
			else p[i] = p[i - 156] ^ (x >> 1);
		}
		x = (p[155] & 0xFFFFFFFF80000000ull) | (p[0] & 0x7FFFFFFFull);
		if (x & 1)p[311] = p[155] ^ (x >> 1) ^ 0xB5026F5AA96619E9ull;
		else p[311] = p[155] ^ (x >> 1);
	}
	//PRandom
	PRandom& PRandom::GetDefaultRef()
	{
		static PObject x;
		if (!x.IsNull())return (PRandom&)x;
		SpinMutex::GetDefaultRef().Lock();
		if (x.IsNull())
		{
			Mt64Random* p = new Mt64Random();
			p->RefCount.SetEnableInterlocked(true);
			x = p;
		}
		SpinMutex::GetDefaultRef().UnLock();
		return (PRandom&)x;
	}

}
#endif
